/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package algoritmos_busqueda;

/**
 *
 * @author stbn
 */
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JOptionPane;
import java.util.Comparator;
import java.util.Collections;

public class BusquedaAStar extends Thread {
    List<Cuadrado> abiertos = new ArrayList<Cuadrado>();
    List<Cuadrado> cerrados = new ArrayList<Cuadrado>();
    Mapa mapa;
    Cuadrado destino;
    
    public BusquedaAStar(Mapa m)
    {
        mapa = m;
    }
    
    public void buscarDestino()
    {
        boolean encontrado = false;
        Cuadrado cuadradoActual;
        List<Cuadrado> vecinos = new ArrayList<Cuadrado>();


        cuadradoActual = mapa.obtenerorigen();
        cuadradoActual.establecerG(0);
        cuadradoActual.establecerH(mapa.obtenerDistanciaManhatan(cuadradoActual));
        cuadradoActual.establecerF(cuadradoActual.obtenerH());

        abiertos.add(cuadradoActual);

        do
        {
            if(abiertos.isEmpty())
            {
                JOptionPane.showMessageDialog(null, "No se ha encontrado el destino");
                encontrado = true;  //para evitar bucle infinito         
            }


            ComparadorF compF = new ComparadorF();
            cuadradoActual = Collections.min(abiertos, compF);
            cuadradoActual.pintar(1);


            abiertos.remove(Collections.min(abiertos, compF));
            
            cerrados.add(cuadradoActual);

            if (cuadradoActual.esDestino())
            {
                encontrado = true;
                //JOptionPane.showMessageDialog(null, "Se ha encontrado el destino");
                destino = cuadradoActual;
            }

            vecinos = mapa.obtenervecinos(cuadradoActual);
            Iterator iteradorVecinos = vecinos.iterator();
            while(iteradorVecinos.hasNext())
            {
                Cuadrado vecinoActual = (Cuadrado) iteradorVecinos.next();

                //JOptionPane.showMessageDialog(null, "basura");
                vecinoActual.pintar(1);

                //vecinoActual.establecerpredecesor(cuadradoActual);
                //vecinoActual.establecerG(cuadradoActual.obtenerG() + vecinoActual.obtenerDificultad());
                //vecinoActual.establecerH(mapa.obtenerDistanciaManhatan(vecinoActual));

                //JOptionPane.showMessageDialog(null, cerrados.contains(vecinoActual));

                if(abiertos.contains(vecinoActual))
                {
                    //JOptionPane.showMessageDialog(null, "basura");
                    //Esto es un fallo: vecinoActual.establecerG(cuadradoActual.obtenerG() + vecinoActual.obtenerDificultad());
                    //Cuadrado vecinoContenido = abiertos.get(abiertos.indexOf(vecinoActual));
                    int gActual = cuadradoActual.obtenerG() + vecinoActual.obtenerDificultad();
                    if (gActual < vecinoActual.obtenerG())
                    {
                        vecinoActual.establecerH(mapa.obtenerDistanciaManhatan(vecinoActual));
                        vecinoActual.establecerG(gActual);
                        vecinoActual.establecerF(vecinoActual.obtenerG() + vecinoActual.obtenerH());
                        vecinoActual.establecerpredecesor(cuadradoActual);
                    }

                    //abiertos.remove(vecinoActual);

                }
                else if(cerrados.contains(vecinoActual))
                {
                    //vecinoActual.establecerG(cuadradoActual.obtenerG() + vecinoActual.obtenerDificultad());
                    //Cuadrado vecinoContenido = cerrados.get(cerrados.indexOf(vecinoActual));
                    int gActual = cuadradoActual.obtenerG() + vecinoActual.obtenerDificultad();
                    if (gActual < vecinoActual.obtenerG())
                    {
                        vecinoActual.establecerH(mapa.obtenerDistanciaManhatan(vecinoActual));
                        vecinoActual.establecerG(cuadradoActual.obtenerG());
                        vecinoActual.establecerF(vecinoActual.obtenerG() + vecinoActual.obtenerH());
                        vecinoActual.establecerpredecesor(cuadradoActual);
                        propagar(vecinoActual);
                    }

                    //cerrados.remove(vecinoActual);
                }
                else
                {
                    vecinoActual.establecerpredecesor(cuadradoActual);
                    vecinoActual.establecerG(cuadradoActual.obtenerG() + vecinoActual.obtenerDificultad());
                    vecinoActual.establecerH(mapa.obtenerDistanciaManhatan(vecinoActual));
                    vecinoActual.establecerF(vecinoActual.obtenerG() + vecinoActual.obtenerH());
                    abiertos.add(vecinoActual);
                }
            }
            


            try
            {
                Thread.currentThread().sleep(101 - Ventana.velocidadPersonaje);
            }
            catch(Exception e)
            {

            }
            while(Ventana.velocidadPersonaje == 0)
            {
                try
            {
                Thread.currentThread().sleep(10);
            }
            catch(Exception e)
            {

            }
            }

        }
        while (!encontrado);
        
    }


    private void propagar (Cuadrado c)
    {
        List <Cuadrado> vecinosPropagacion = mapa.obtenervecinos(c);
        Iterator iteradorPropagacion = vecinosPropagacion.iterator();
            while(iteradorPropagacion.hasNext())
            {
                Cuadrado vecinoActual = (Cuadrado) iteradorPropagacion.next();

                if (vecinoActual.obtenerpredecesor() == c)
                {
                    vecinoActual.establecerG(c.obtenerG() + vecinoActual.obtenerDificultad());
                    vecinoActual.establecerH(mapa.obtenerDistanciaManhatan(vecinoActual));
                    vecinoActual.establecerF(vecinoActual.obtenerG() + vecinoActual.obtenerH());
                    propagar(vecinoActual);
                }
                else
                {
                    vecinoActual.establecerG(c.obtenerG() + vecinoActual.obtenerDificultad());
                    vecinoActual.establecerH(mapa.obtenerDistanciaManhatan(vecinoActual));
                    vecinoActual.establecerF(vecinoActual.obtenerG() + vecinoActual.obtenerH());
                    vecinoActual.establecerpredecesor(c);
                    propagar(vecinoActual);
                }


            }
    }

    

    class ComparadorF implements Comparator
    {
        public int compare(Object c1, Object c2)
        {
            Cuadrado cuadrado1 = (Cuadrado) c1;
            Cuadrado cuadrado2 = (Cuadrado) c2;
            return cuadrado1.obtenerF() - cuadrado2.obtenerF();

        }
    }


    public void dibujarCamino()
    {
        Cuadrado cuadradoActual = destino;

        while(cuadradoActual != mapa.obtenerorigen())
        {
            cuadradoActual.pintar(2);
            if (!cuadradoActual.obtenerpredecesor().esobstaculo()) cuadradoActual = cuadradoActual.obtenerpredecesor();
            try
            {
                Thread.currentThread().sleep(101 - Ventana.velocidadPersonaje);
            }
            catch(Exception e)
            {

            }
            while(Ventana.velocidadPersonaje == 0)
            {
                try
            {
                Thread.currentThread().sleep(10);
            }
            catch(Exception e)
            {

            }
            }
        }
        cuadradoActual.pintar(2);

    }

    public void run()
    {
        buscarDestino();
        dibujarCamino();
    }

}
